package com.franklin.java.api.spring.annotation.bean;

import com.franklin.java.api.annotation.BaseAnnotation;
import com.franklin.plugins.common.collection.PrettyArrayList;
import com.franklin.plugins.common.collection.PrettyHashSet;
import com.franklin.java.utils.PsiUtils;
import com.franklin.plugins.common.utils.DataCheckUtils;
import com.franklin.plugins.common.utils.StringHelper;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;

import java.util.*;

/**
 * @author Franklin
 * @since 2021/8/13 14:17
 */
public class BeanAnnotations extends BaseAnnotation {

    static {
        annotationMap.put(new Bean());
        annotationMap.put(new Controller());
        annotationMap.put(new RestController());
        annotationMap.put(new Service());
        annotationMap.put(new Component());
        annotationMap.put(new Repository());
        annotationMap.put(new ApacheDubboService());
        annotationMap.put(new AlibabaDubboService());
        annotationMap.put(new Mapper());
    }

    protected BeanAnnotations() {
        super(null, null);
    }

    public static BeanAnnotation parse(PsiAnnotation psiAnnotation) {
        BeanAnnotation beanAnnotation = BaseAnnotation.parse(psiAnnotation, BeanAnnotation.class);
        if (Objects.isNull(beanAnnotation)) {
            return null;
        }
        //生成beanName

        Set<String> defaultBeanNames = getDefaultBeanNames(psiAnnotation);
        String beanName = getBeanName(psiAnnotation, "value", getBaseDefault(psiAnnotation));

        defaultBeanNames.add(beanName);

        defaultBeanNames = beanAnnotation.addSuffix(defaultBeanNames);

        //生成新对象
        BeanAnnotation newBeanAnn = new BeanAnnotation(
                beanAnnotation.getQualifiedName(),
                beanAnnotation.getShortName(),
                defaultBeanNames
        ) {
        };
        return newBeanAnn;
    }

    private static Set<String> getDefaultBeanNames(@NotNull PsiAnnotation psiAnnotation) {
        Set<String> beanNames = new PrettyHashSet<>();
        PsiClass psiClass = PsiTreeUtil.getParentOfType(psiAnnotation, PsiClass.class);
        if (Objects.isNull(psiClass)) {
            return beanNames;
        }
        List<PsiClassType> parentList = new PrettyArrayList<>();
        PsiClassType[] implementsListTypes = psiClass.getImplementsListTypes();
        Collections.addAll(parentList, implementsListTypes);
        PsiClassType[] extendsListTypes = psiClass.getExtendsListTypes();
        Collections.addAll(parentList, extendsListTypes);

        for (PsiClassType psiClassType : parentList) {
            beanNames.add(StringHelper.firstToLowerCase(psiClassType.getName()));
        }

        return beanNames;
    }

    @NotNull
    private static String getBaseDefault(@NotNull PsiAnnotation psiAnnotation) {
        return StringHelper.firstToLowerCase(psiAnnotation.getContainingFile().getName());
    }

    @NotNull
    protected static String getBeanName(PsiAnnotation psiAnnotation, String valueAttributeName, String defaultBeanName) {
        if (Objects.isNull(psiAnnotation)) {
            return "";
        }
        String annotationAttributeValue = PsiUtils.getAnnotationAttributeValue(psiAnnotation, valueAttributeName);
        if (DataCheckUtils.isNotEmpty(annotationAttributeValue)){
            return StringHelper.firstToLowerCase(annotationAttributeValue);
        }

        //生成默认beanName
        return StringHelper.firstToLowerCase(defaultBeanName);
    }

    private static class Bean extends BeanAnnotation {
        private Bean() {
            super("org.springframework.context.annotation.Bean", "Bean", null);
        }
    }

    private static class Controller extends BeanAnnotation {

        private Controller() {
            super("org.springframework.stereotype.Controller", "Controller", null);
        }

    }

    private static class RestController extends BeanAnnotation {
        private RestController() {
            super("org.springframework.web.bind.annotation.RestController", "RestController", null);
        }
    }

    private static class Service extends BeanAnnotation {
        private Service() {
            super("org.springframework.stereotype.Service", "Service", null);
        }
    }

    private static class Component extends BeanAnnotation {
        private Component() {
            super("org.springframework.stereotype.Component", "Component", null);
        }
    }

    private static class Repository extends BeanAnnotation {
        private Repository() {
            super("org.springframework.stereotype.Repository", "Repository", null);
        }
    }

    private static class ApacheDubboService extends BeanAnnotation {

        private ApacheDubboService() {
            super("org.apache.dubbo.config.annotation.Service", "Service", null);
        }

        @Override
        protected String getSuffix() {
            return ":" + PsiUtils.getAnnotationAttributeValue(psiAnnotation,"version");
        }
    }

    private static class AlibabaDubboService extends BeanAnnotation {
        private AlibabaDubboService() {
            super("com.alibaba.dubbo.config.annotation.Service", "Service", null);
        }

        @Override
        protected String getSuffix() {
            return ":" + PsiUtils.getAnnotationAttributeValue(psiAnnotation,"version");
        }
    }

    private static class Mapper extends BeanAnnotation {
        private Mapper() {
            super("org.apache.ibatis.annotations.Mapper", "Mapper", null);
        }
    }
}
